﻿// sender.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
#include "serialport.h"
#include <windows.h>
#include <mmsystem.h>
#include <sstream>

#pragma comment(lib, "winmm.lib")

uint8_t pitch = 0;
uint8_t roll = 0;
uint8_t pressure = 0;
uint8_t acc_x = 0;
uint8_t acc_y = 0;
uint8_t acc_z = 0;

// 全局变量，存储串口数组和对应的异步写信息
SerialPort* g_serialports = nullptr;

void sendCompass(SerialPort& serialport, int index) {
    uint8_t comp[] = { 0x68, 0x0D, 0x00, 0x84, 0x10, pitch, 0x80, 0x00, roll, 0x65, 0x03, 0x13, 0x71, 0x00 };

    comp[13] = 0;

    for (uint8_t i = 1; i < sizeof(comp) - 1; i++) {
        comp[13] += comp[i];
    }

    pitch++;
    roll++;

    if (serialport.write(reinterpret_cast<const char*>(comp), sizeof(comp))) {
        std::cout << "Compass 数据写入成功" << std::endl;
    }
    else {
        std::cout << "Compass 数据写入失败" << std::endl;
    }
}

void sendDepth(SerialPort& serialport, int index) {
    std::ostringstream oss;
    oss << "P " << pressure + 0.25 << "\r\n";
    std::string strs = oss.str();

    pressure++;

    if (serialport.write(strs.c_str(), strs.length())) {
        std::cout << "Depth 数据写入成功" << std::endl;
    }
    else {
        std::cout << "Depth 数据写入失败" << std::endl;
    }
}

void sendGuidance(SerialPort& serialport, int index) {
    static uint8_t guid[] = {
        0x55, 0xAA, 0xA0, 0xA1,
        0x02, 0x03, 0x30, 0x40,
        0x50, 0x03, 0x05, 0x05,
        0x32, 0x03, 0x05, 0x05,
        0x02, pitch, pitch, 0x05,
        0x02, roll, roll, 0x05,
        pitch, pitch, pitch, 0x05,
        0x02, roll, roll, 0x05,
        pitch, 0x03, 0x05, 0x05,
        0x02, 0x03, 0x05, 0x02,
        0x03, 0x05, pitch, pitch,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, roll,
        pitch, 0x05, 0x05, 0x02,
        0x03, 0x05, pitch, pitch,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        pitch, 0x05, 0x05, 0x02,
        0x03, 0x05, roll, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, roll, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x02,
        0x03, 0x05, pitch, 0x02,
        pitch, 0x05, 0x05, 0x02,
        0x03, 0x05, 0x05, 0x00,
        //0x04, 0x04, 0x30
    };

    guid[159] = 0;
    for (int i = 0; i < sizeof(guid) - 1; i++) {
        guid[159] = guid[159] ^ guid[i];
    }

    if (serialport.write(reinterpret_cast<const char*>(guid), sizeof(guid))) {
        std::cout << "Guidance 数据写入成功" << std::endl;
    }
    else {
        std::cout << "Guidance 数据写入失败" << std::endl;
    }
}

void sendPosture(SerialPort& serialport, int index) {
    static uint8_t post[] = { 0x59, 0x53, 0x40, 0x92, 0x5C,
                                0x01, 0x02, acc_x, acc_y,
                                0x10, 0x0c, acc_x, acc_y, acc_x, acc_y, acc_z, acc_x, acc_x, acc_y, acc_z, acc_x, acc_x, 0xff,
                                0x20, 0x0c, acc_x, acc_x, acc_x, acc_x, acc_y, acc_y, acc_y, acc_y, acc_y, acc_z, acc_z, 0x00,
                                0x30, 0x0c, 0x00, 0x00, 0xf1, 0x07, 0xd0, 0xa0, 0xea, 0xf4, 0xc0, 0x8e, 0xc6, 0xef,
                                0x31, 0x0c, 0x00, 0x03, 0x02, 0x00, 0xa2, 0x29, 0xfd, 0xff, 0xb8, 0xd8, 0xfb, 0xff,
                                0x40, 0x0c, 0x00, 0x03, 0xf4, 0xff, 0xb1, 0xbe, 0x09, 0x00, 0x30, 0x32, 0xb6, 0xf6,
                                0x41, 0x10, 0x00, 0x04, 0x03, 0x00, 0x4d, 0xec, 0xff, 0xff, 0x86, 0xe5, 0xff, 0xff, 0xa9, 0x14, 0xf1, 0xff, 0x00, 0x00 };

    post[sizeof(post) - 1] = 0;
    post[sizeof(post) - 2] = 0;

    for (int i = 2; i < sizeof(post) - 2; i++) {
        post[sizeof(post) - 2] = post[sizeof(post) - 2] + post[i];
        post[sizeof(post) - 1] = post[sizeof(post) - 1] + post[sizeof(post) - 2];
    }

    if (serialport.write(reinterpret_cast<const char*>(post), sizeof(post))) { 
        std::cout << "Posture 数据写入成功" << std::endl;
    }
    else {
        std::cout << "Posture 数据写入失败" << std::endl;
    }
}

#define CBR_115200 115200
#define CBR_230400 230400
#define CBR_460800 460800


VOID CALLBACK CompassTimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
    sendCompass(g_serialports[0], 0);
    std::cout << "compass\n";
}

VOID CALLBACK DepthTimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
    sendDepth(g_serialports[1], 1);
    std::cout << "depth\n";
}

VOID CALLBACK GuidanceTimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
    sendGuidance(g_serialports[2], 2);
    std::cout << "guidance\n";
}

VOID CALLBACK PostureTimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2) {
    sendPosture(g_serialports[3], 3);
    std::cout << "posture\n";
}

int main()
{
    SerialPort serialports[6];
    g_serialports = serialports;

    serialports[0].open(std::wstring(L"COM1"), CBR_57600); // compass
    serialports[1].open(std::wstring(L"COM3"), CBR_57600); // depth
    serialports[2].open(std::wstring(L"COM5"), CBR_230400); // guidance
    serialports[3].open(std::wstring(L"COM7"), CBR_460800); // posture
    serialports[4].open(std::wstring(L"COM9"), CBR_115200); // location
    serialports[5].open(std::wstring(L"COM11"), CBR_115200); // vialog

    for (int i = 0; i < 6; i++) {
        if (!serialports[i].isOpen()) {
            std::cout << "nowadays " << i << " is not open\n";
        }
    }

    // 创建独立的定时器
    UINT compassTimerId = timeSetEvent(30, 1, CompassTimerCallback, 0, TIME_PERIODIC);
    if (compassTimerId == 0) {
        std::cerr << "Failed to set compass timer." << std::endl;
        timeKillEvent(compassTimerId);
        return 1;
    }

    UINT depthTimerId = timeSetEvent(30, 1, DepthTimerCallback, 0, TIME_PERIODIC);
    if (depthTimerId == 0) {
        std::cerr << "Failed to set depth timer." << std::endl;
        timeKillEvent(depthTimerId);
        return 1;
    }

    UINT guidanceTimerId = timeSetEvent(30, 1, GuidanceTimerCallback, 0, TIME_PERIODIC);
    if (guidanceTimerId == 0) {
        std::cerr << "Failed to set guidance timer." << std::endl;
        timeKillEvent(guidanceTimerId);
        return 1;
    }

    UINT postureTimerId = timeSetEvent(30, 1, PostureTimerCallback, 0, TIME_PERIODIC);
    if (postureTimerId == 0) {
        std::cerr << "Failed to set posture timer." << std::endl;
        timeKillEvent(postureTimerId);
        return 1;
    }

    std::cout << "Hello World!\n";

    // 等待用户输入以退出程序
    std::cin.get();

    // 停止所有定时器
    timeKillEvent(compassTimerId);
    timeKillEvent(depthTimerId);
    timeKillEvent(guidanceTimerId);

    return 0;
}
// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
